package com.fatri.lessionsimple.opengl.drawer

import android.content.Context
import android.opengl.GLES20
import android.opengl.Matrix
import com.fatri.lessionsimple.opengl.IDrawer
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import java.nio.ShortBuffer

/**
 * 带相机变换矩阵的三角形
 */
class RectangleDrawer(ctx: Context) : IDrawer(ctx) {


    private val vertexShaderCode = "attribute vec4 vPosition;" +
            "uniform mat4 vMatrix;" +
            "varying  vec4 vColor;" +
            "attribute vec4 aColor;" +
            "void main() {" +
            "  gl_Position =  vMatrix*vPosition;" +
            "vColor=aColor;" +
            "}"

    private val fragmentShaderCode = "precision mediump float;" +
            "varying vec4 vColor;" +
            "void main() {" +
            "  gl_FragColor = vColor;" +
            "}"

    private var mProgram = 0
    private lateinit var vertexBuffer: FloatBuffer


    val COORDS_PER_VERTEX = 3
    var triangleCoords = floatArrayOf(
        -0.5f, -0.5f, 0.0f,  // top
        0.5f, -0.5f, 0.0f,  // bottom left
        -0.5f, 0.5f, 0.0f, // bottom right
        0.5f, 0.5f, 0.0f
    )

    /**
     * 使用顶点索引画法
     * 由于使用的是GL_TRIANGLE_STRIP，所以顶点复用，012为三角形，123另一个三角形
     * 索引分别对应triangleCoords顶点坐标的每个float值
     */
    val index = shortArrayOf(
        0, 1, 2, 1, 2, 3
    )

    private var mPositionHandle = 0
    private var mColorHandle = 0


    //顶点个数
    private val vertexCount = triangleCoords.size / COORDS_PER_VERTEX

    //一个顶点占有的总字节数
    private val vertexStride = COORDS_PER_VERTEX * 4 // 每个顶点包括3个float，一个float四字节


    private val mViewMatrix = FloatArray(16)
    private val mProjectMatrix = FloatArray(16)
    private val mMVPMatrix = FloatArray(16)


    //设置颜色
    var color = floatArrayOf(
        1.0f, 0.0f, 0.0f, 1.0f,
        0.0f, 1.0f, 0.0f, 1.0f,
        0.0f, 0.0f, 1.0f, 1.0f,
        1.0f, 0.0f, 1.0f, 1.0f
    )
    lateinit var colorBuffer: FloatBuffer
    lateinit var indexBuffer: ShortBuffer
    override fun onSurfaceCreated() {
        val bb = ByteBuffer.allocateDirect(triangleCoords.size * 4)
        bb.order(ByteOrder.nativeOrder())
        vertexBuffer = bb.asFloatBuffer()
        vertexBuffer.put(triangleCoords)
        vertexBuffer.position(0)


        //转换颜色着色器数据
        val cc = ByteBuffer.allocateDirect(color.size * 4)
        cc.order(ByteOrder.nativeOrder())
        colorBuffer = cc.asFloatBuffer()
        colorBuffer.put(color)
        colorBuffer.position(0)


        //转换索引到缓冲
        val ss = ByteBuffer.allocateDirect(index.size * 2)
        ss.order(ByteOrder.nativeOrder())
        indexBuffer = ss.asShortBuffer()
        indexBuffer.put(index)
        indexBuffer.position(0)

        val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode)
        val fragShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode)

        mProgram = GLES20.glCreateProgram()
        GLES20.glAttachShader(mProgram, vertexShader)
        GLES20.glAttachShader(mProgram, fragShader)
        GLES20.glLinkProgram(mProgram)


    }

    override fun onSurfaceChanged(width: Int, height: Int) {
        var ratio = (width * 1.0 / height).toFloat()
//        ratio = 1.0f
        //设置透视投影
        print("width:${width},height:${height},ratio:$ratio\n")

        /**
         * 解释:
         * r=w/h  ，宽/高
         * 坐标点区间 x∈[-w/2,w/2]  ，y∈[-h/2,h/2]
         * 当希望充满X轴时，x从[-w/2,w/2]映射到[-1,1] ，则x和y都需要除以 w/2 ，得到 x∈[-1,1],y∈[-1/r,1/r]
         * 当希望充满Y轴时，y从[-h/2,h/2]映射到[-1,1] ，则x和y都需要除以 h/2 ，得到 x∈[-r,r],y∈[-1,1 ]
         *
         * near 和far与相机矩阵有关
         */
        Matrix.frustumM(
            mProjectMatrix, 0
            , -1f, 1f, -1f / ratio, 1f / ratio, 3f, 7f
        )
        printArr(mProjectMatrix)
        //设置相机位置
        Matrix.setLookAtM(
            mViewMatrix, 0,
            0f, 0f, 7.0f,   //eyeZ=7表示相机位置设置在目标正前方
            0f, 0f, 0f,//目标的坐标

            0.0f, 1.0f, 0.0f
        )  //up为三个向量，合成的方向才是相机最终的方向，
        //若（0，1，0）为正视目标，则（1，1，0）旋转了45°
        //计算变换矩阵
        Matrix.multiplyMM(
            mMVPMatrix, 0,
            mProjectMatrix, 0,
            mViewMatrix, 0
        )


    }

    fun printArr(arr: FloatArray) {
        for (i in 0 until arr.size) {
            if (i % 4 == 0) print("\n")
            print("${arr[i]},")

        }

    }

    override fun onDrawFrame() {

        GLES20.glUseProgram(mProgram)
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition")
        GLES20.glEnableVertexAttribArray(mPositionHandle)
        GLES20.glVertexAttribPointer(
            mPositionHandle,
            COORDS_PER_VERTEX,  //顶点数据个数
            GLES20.GL_FLOAT,
            false,
            vertexStride, //顶点占有的字节总数
            vertexBuffer
        )

        //给vMatrix赋值
        val mMatrixHandler = GLES20.glGetUniformLocation(mProgram, "vMatrix")
        GLES20.glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrix, 0)

        //给aColor赋值
        val colorHandler = GLES20.glGetAttribLocation(mProgram, "aColor")
        GLES20.glEnableVertexAttribArray(colorHandler)
        GLES20.glVertexAttribPointer(
            colorHandler, 4, GLES20.GL_FLOAT, false,
            0, colorBuffer
        )


//        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6)  //如果用GL_TRIANGLES，得传六个顶点，每三个点画一个三角形
//        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)  //如果用GL_TRIANGLE_STRIP，画两个三角形得传4个点，N个三角形N+2个点

        GLES20.glDrawElements(
            GLES20.GL_TRIANGLE_STRIP,
            index.size,
            GLES20.GL_UNSIGNED_SHORT,
            indexBuffer
        )

        //禁止顶点数组的句柄
        GLES20.glDisableVertexAttribArray(mPositionHandle)

    }

    override fun release() {
    }

}